import { useState } from "react";
import styles from "./index.less";
import { Input, Button } from "antd";
import ExcelJS from "exceljs";
import { testHTML } from './data';

const { TextArea } = Input;

type TextCell = {
    type: 'Text';
    text: string;
    bold?: boolean;
    width?: number;
    height?: number;
    fontSize?: number;
    color?: string;
};

type ImageCell = {
    type: 'Image';
    row: number;
    col: number;
    url: string;
    base64: string;
    width: number;
    height: number;
};

type Cell = TextCell | ImageCell;

export default () => {
    const [htmlString, setHtmlString] = useState<string>(testHTML);

    const [parseHtml, setParseHtml] = useState<string>("");

    const onInputChange = (e: any) => {
        console.log(e.target.value);
        setHtmlString(e.target.value || "");
    };

    // 点击解析
    const onParseClick = async () => {
        const parse = processHtmlString();
        setParseHtml(parse);
        console.log(parse);
        console.log('----------------------------------------------------------------------------------------------------------------');
    };

    // 从原始的打印模板HTML字符串中，解析出能正确渲染的HTML文档
    const processHtmlString = () => {
        const hasHtmlEnd = htmlString.includes("</html>");
        const subHtmlString = hasHtmlEnd
            ? htmlString.substring(0, htmlString.indexOf("</html>") + 7)
            : "";

        if (!subHtmlString) {
            return "";
        }

        // 处理可能的转义字符
        let processedHtml = subHtmlString
            // 替换可能的转义符
            .replace(/&amp;/g, "&")
            .replace(/&lt;/g, "<")
            .replace(/&gt;/g, ">")
            .replace(/&quot;/g, '"')
            .replace(/&#39;/g, "'")
            // 清理不必要的data-mce-style属性
            .replace(/ data-mce-style="[^"]*"/g, "")
            // 处理可能的空样式属性
            .replace(/ style=""/g, "")
            // 处理表格宽度可能存在的小数问题
            .replace(
                /width: (\d+\.\d+)px/g,
                (match, num) => `width: ${Math.round(parseFloat(num))}px`
            )
            ;

        // 返回完整的HTML文档字符串
        return `<!DOCTYPE html>\n${processedHtml}`;
    };

    // 点击导出
    const onExportClick = async () => {
        const fileName = '测试Excel';
        try {
            // 检查ExcelJS库是否加载
            if (typeof ExcelJS === "undefined") {
                return;
            }

            // 1. 创建工作簿和工作表
            const workbook = new ExcelJS.Workbook();
            const worksheet = workbook.addWorksheet("订单数据");

            // 2. 提取所有内容数据并添加到工作表
            const allData = extractAllContent();
            const maxColumnCount = getMaxColumnCount(allData);
            console.log(allData);

            const imageCells: ImageCell[] = [];
            // 3. 添加数据到工作表
            allData.forEach((row, rowIndex) => {
                // 默认第一行是主标题，且只有一个元素，不能改，所有模板都遵守。合并单元格并设置标题样式
                if (rowIndex === 0) {
                    const cell: TextCell = row[0] as TextCell;
                    const excelRow = worksheet.addRow([cell.text]);
                    worksheet.getRow(1).height = 36;
                    worksheet.mergeCells(1, 1, 1, maxColumnCount); // 合并6列
                    excelRow.font = { bold: cell.bold, size: cell.fontSize };
                    excelRow.alignment = {
                        horizontal: "center",
                        vertical: "middle",
                    };
                    excelRow.height = 30;
                } else if (row.length === 1) { // 如果是单列，则合并单元格
                    const cell: TextCell = row[0] as TextCell;
                    const excelRow = worksheet.addRow([cell.text]);
                    worksheet.mergeCells(rowIndex + 1, 1, rowIndex + 1, maxColumnCount);
                    excelRow.font = { bold: cell.bold, size: cell.fontSize };
                    excelRow.alignment = {
                        horizontal: "left",
                        vertical: "middle",
                    };
                } else { //普通行
                    row.forEach((cell, cellIndex) => {
                        if (cell.type == 'Text') {
                            worksheet.getColumn(cellIndex + 1).width = cell.width;
                            if (isMobile(cell.text)) {
                                worksheet.getCell(rowIndex + 1, cellIndex + 1).value = Number(cell.text);
                                worksheet.getCell(rowIndex + 1, cellIndex + 1).numFmt = '0'
                            } else if (isNumeric(cell.text)) {
                                worksheet.getCell(rowIndex + 1, cellIndex + 1).value = Number(cell.text);
                                worksheet.getCell(rowIndex + 1, cellIndex + 1).numFmt = '0.00'
                            } else {
                                worksheet.getCell(rowIndex + 1, cellIndex + 1).value = cell.text;
                            }
                            worksheet.getCell(rowIndex + 1, cellIndex + 1).font = {
                                size: cell.fontSize,          // 字体大小
                                bold: cell.bold,        // 加粗
                                color: { argb: cell.color || 'FF000000' }
                            };
                        } else if (cell.type == 'Image') {
                            imageCells.push({...cell, row: rowIndex});
                        } else {
                            // TODO 未知类型
                        }
                    });
                }
            });

            // 4. 处理图片
            const images = await loadImages(imageCells);
            if (images.length > 0) {
                // 循环添加图片到工作表
                for (const [index, img] of images.entries()) {
                    console.log(`## 图片元素 img=${JSON.stringify(img)}`);
                    try {
                        // 计算图片在Excel中的实际位置
                        const excelRow = img.row + 1; // ExcelJS行索引从1开始
                        const excelCol = img.col + 1; // ExcelJS列索引从1开始

                        // 设置行高以容纳图片
                        worksheet.getRow(excelRow).height = 120;

                        // 将图片添加到工作表
                        const imageId = workbook.addImage({
                            base64: img.base64,
                            extension: "jpeg",
                        });

                        // 嵌入图片到工作表
                        worksheet.addImage(imageId, {
                            tl: { col: excelCol - 1, row: excelRow - 1 },
                            ext: { width: img.width, height: img.height }, // 调整图片大小以适应单元格
                            editAs: "oneCell",
                        });
                        console.log(`成功添加图片 ${index + 1}/${images.length} 到工作表`
                        );
                    } catch (imgError: any) {
                        console.log(`处理图片 ${index + 1} 失败: ${imgError.message}`);
                    }
                }
            }

            // 5. 导出文件
            const buffer = await workbook.xlsx.writeBuffer();
            const blob = new Blob([buffer], {
                type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            });
            const url = URL.createObjectURL(blob);
            const a = document.createElement("a");
            a.href = url;
            a.download = `${fileName}.xlsx`;
            a.click();
            URL.revokeObjectURL(url);
        } catch (error: any) {
            const errorMsg = `导出失败: ${error.message}`;
            console.log(errorMsg);
            console.error(error);
        }
    };

    // 提取页面中所有需要导出的内容
    const extractAllContent = (): Cell[][] => {
        const allData: Cell[][] = [];

        // 1. 解析head数据
        const headDiv = document.getElementById("theadid");
        if (headDiv) {
            const headData: Cell[][] = [];
            const ps = headDiv.querySelectorAll('p');
            ps.forEach((p, index) => {
                if (index == 0) {
                    headData.push([{ type: 'Text', text: p.innerText, fontSize: 20, height: 30, bold: true }]);
                } else {
                    headData.push([{ type: 'Text', text: p.innerText, fontSize: 12 }]);
                }
            })
            // 添加空行
            headData.push([{ type: 'Text', text: '' }]);
            allData.push(...headData);
        }

        // 2. 解析table数据
        const tbodyDiv = document.getElementById("tbodyid");
        if (tbodyDiv) {
            const tableData: Cell[][] = [];
            const table = tbodyDiv.querySelector("table");
            if (table) {
                const rows = table.querySelectorAll("tr");

                rows.forEach((row, rowIndex) => {
                    const rowData: Cell[] = [];
                    const cells = row.querySelectorAll("td");
                    cells.forEach((cell, cellIndex) => {
                        const child = cell.children[0];
                        if (child) {
                            if (child.tagName?.toLowerCase() == 'customimg') {
                                const url = child.getAttribute('url');
                                const width = child.getAttribute('width');
                                const height = child.getAttribute('height');
                                rowData.push({ type: 'Image', url: url || '', base64: '', width: width ? parseInt(width) : 100, height: height ? parseInt(height) : 100, row: rowIndex, col: cellIndex });
                            } else if (child.tagName?.toLowerCase() == 'strong') {
                                const width = getStyleValue(cell.getAttribute('style') || '', 'width');
                                rowData.push({ type: 'Text', text: cell.innerText, width: width ? parseInt(width) / 2.5 : 20, fontSize: 12, bold: true, color: 'ff1876ff' });
                            } else {
                                const width = getStyleValue(cell.getAttribute('style') || '', 'width');
                                rowData.push({ type: 'Text', text: cell.innerText, width: width ? parseInt(width) / 2.5 : 20, fontSize: 12 });
                            }
                        } else {
                            const width = cell.getAttribute('width');
                            rowData.push({ type: 'Text', text: cell.innerText, width: width ? parseInt(width) / 2.5 : 20, fontSize: 12 });
                        }
                    });
                    tableData.push(rowData);
                });
            } else {
                const ps = tbodyDiv.querySelectorAll('p');
                ps.forEach(p => {
                    tableData.push([{ type: 'Text', text: p.innerText, fontSize: 12 }]);
                })
            }

            // 添加空行
            tableData.push([{ type: 'Text', text: '' }]);
            allData.push(...tableData);
        }

        // 4. 提取tfootid div内容
        const tfootDiv = document.getElementById("tfootid");
        if (tfootDiv) {
            const footData: Cell[][] = [];
            const ps = tfootDiv.querySelectorAll('p');
            ps.forEach(p => {
                footData.push([{ type: 'Text', text: p.innerText, fontSize: 12 }]);
            })
            allData.push(...footData);
        }

        return allData;
    };

    function loadImageAndConvertToBase64(url: string, timeout = 10000) {
        return new Promise((resolve, reject) => {
            const timer = setTimeout(() => {
                reject(new Error(`图片加载超时: ${url}`));
            }, timeout);
            
            const img = new Image();
            img.crossOrigin = 'anonymous';
            
            img.onload = function() {
                clearTimeout(timer);
                try {
                    const canvas = document.createElement('canvas');
                    canvas.width = img.naturalWidth || img.width;
                    canvas.height = img.naturalHeight || img.height;
                    const ctx: CanvasRenderingContext2D | null = canvas.getContext('2d');
                    ctx?.drawImage(img, 0, 0);

                    try {
                        const base64 = canvas.toDataURL('image/jpeg').split(',')[1];
                        resolve(base64);
                    } catch (canvasError: any) {
                        reject(new Error(`图片处理失败: ${canvasError.message}`));
                    }
                } catch (error: any) {
                    reject(new Error(`图片转换失败: ${error.message}`));
                }
            };
            
            img.onerror = (error: any) => {
                clearTimeout(timer);
                reject(new Error(`图片加载失败: ${url} - ${error.message || '未知错误'}`));
            };
            img.src = url;
        });
    }

    /**
     * 加载所有图片元素的base64
     */
    const loadImages = async (imageCells: ImageCell[]) => {
        const images: ImageCell[] = [];

        for (let i = 0; i < imageCells.length; i++) {
            const item = imageCells[i];
            if (!item.url) {
                continue;
            }
            const base64: string = await loadImageAndConvertToBase64(item.url) as string;
            if (!base64) {
                continue;
            }
            images.push({...item, base64});
        }

        return images;
    };

    return (
        <div className={styles.container}>
            <div className={styles.left}>
                <p className={styles.subTitle}>请输入HTML文档字符串</p>
                <TextArea
                    className={styles.inputArea}
                    value={htmlString}
                    onChange={onInputChange}
                />
                <Button
                    id='parse'
                    className={styles.parseHTML}
                    onClick={onParseClick}
                    type="primary"
                >
                    解析HTML
                </Button>
                <Button
                    id='export'
                    className={styles.exportExcel}
                    onClick={onExportClick}
                    type="primary"
                >
                    导出Excel
                </Button>
            </div>

            <div
                className={styles.right}
                dangerouslySetInnerHTML={{ __html: parseHtml }}
            />
        </div>
    );
};

const getMaxColumnCount = (data: Cell[][]) => {
    if (!data?.length) {
        return 0;
    }
    let count = 0;
    data.forEach(i => {
        if (i.length > count) {
            count = i.length;
        }
    })
    return count;
}

/**
 * 从 style 字符串中提取指定 CSS 属性值
 * @param styleText 形如 `width: 48px; height: 20px;`
 * @param prop      要取的属性名，如 `width`
 * @returns         找到返回对应值（自动去掉首尾空格），未找到返回 null
 */
const getStyleValue = (styleText: string, prop: string): string | null => {
    // (?<=^|;\\s*)  确保属性出现在开头或紧跟分号+空格
    // ([^;]*)      捕获除分号外的任意字符
    const regex = new RegExp(`(?<=^|;\\s*)${prop}\\s*:\\s*([^;]+)(?=;|$)`, 'i');
    const match = styleText.match(regex);
    return match ? match[1].trim() : null;

    // (?<=…) 和 (?=…) 是 ES2018 才加入的 lookbehind / lookahead 断言。
    // Chrome、Safari、Edge 等现代浏览器已支持。
    // React-Native（Hermes 引擎，Android） 目前 不支持 lookbehind，于是运行时报：
}

/**
 * 从 style 字符串中提取指定 CSS 属性值（非正则表达式）
 */
const getStyleValue2 = (styleText: string, prop: string): string | null => {
    if (!styleText || !prop) {
        return null;
    }
    const arr = styleText.split(';');
    if (!arr.length) {
        return null;
    }
    let result = null;
    for (let i = 0; i < arr.length; i++) {
        const item = arr[i];
        if (item && item.includes(':')) {
            const pair = item.trim().split(':');
            if (pair?.length == 2) {
                const key = pair[0];
                const value = pair[1];
                if (key == prop) {
                    result = value;
                    break;
                }
            }
        }
    }
    return result;
};

// 判断是否是合法的手机号（中国大陆 11 位，1 开头，第三位按运营商号段）
const isMobile = (str: string): boolean => {
    if (!str) {
        return false;
    }
    const reg = /^1[3-9]\d{9}$/;
    return reg.test(str);
}
  
// 判断是否是合法数值（整数/小数/正负号/科学计数法均可）
const isNumeric = (str: string): boolean => {
    if (!str) {
        return false;
    }
    return !Number.isNaN(Number(str)) && str.trim() !== '';
}
